#  ping_daemon.rb
#
#  This file is part of myvnet.
#
#  Copyright (C) 2008  Filipe David Borba Manana,  fdmanana@gmail.com
#
#  myvnet is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  myvnet is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with myvnet.  If not, see <http://www.gnu.org/licenses/>.
 

require 'lib/daemons/generic_daemon'


module Daemon
  
  # A daemon whose task is to reply to pings (ICMP Echo requests)
  # destined to the supplied IP addresses.
  #
  class PingDaemon < Daemon::GenericDaemon
        
    def initialize(name, packet_injector, hwaddress, *net_addresses)
      super
      
      @packet_filter = ""
      @ip_id_field = {}
      
      @net_addresses.each do |addr|
        @packet_filter << "(icmp and dst host #{addr}) or "
        
        @ip_id_field[addr] = (rand 0x54_af) + 0x1b_3e
      end
      
      @packet_filter[-4,4] = ''     
    end
    
    
    def process(packet)
      return unless packet.has_icmp?
      
      ip_pkt = packet.payload 

      unless ip_pkt.payload.type == :echo_request and
             @net_addresses.include? ip_pkt.dst
        return
      end

      eth_reply = packet.dup      
      eth_reply.dst, eth_reply.src = eth_reply.src, eth_reply.dst
      
      ip_reply = eth_reply.payload      
      ip_reply.dst, ip_reply.src = ip_reply.src, ip_reply.dst
      ip_reply.id = get_next_ip_id(ip_pkt.dst)      
      
      icmp_reply = ip_reply.payload
      icmp_reply.type = :echo_reply
      
      icmp_reply.checksum = 0  # for auto calculation            
      ip_reply.checksum = 0  # for auto calculation
      
      inject eth_reply
                  
      true # packet processed
    end
    
    
    private
    
    def get_next_ip_id(address)
      if @ip_id_field[address] > 0xef_ff
        @ip_id_field[address] = (rand 0x54_af) + 0x1b_3e
      end
      
      @ip_id_field[address] += 1
    end
    
  end
  
end
